/*
* Copyright (C) 1997-2001 Id Software, Inc.
* 
* This program is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License as published by the Free Software
* Foundation; either version 2 of the License, or (at your option) any later
* version.
* 
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE.
* 
* See the GNU General Public License for more details.
* 
* You should have received a copy of the GNU General Public License along with
* this program; if not, write to the Free Software Foundation, Inc., 59 Temple
* Place - Suite 330, Boston, MA 02111-1307, USA.
*  
*/

// Created on 14.01.2004 by RST.
// $Id: SV_GAME.java,v 1.10 2006/01/21 21:53:32 salomo Exp $
using System;
using Defines = Suake2.UI.Defines;
using Globals = Suake2.UI.Globals;
using Suake2.UI.game;
using Suake2.UI.qcommon;
using Math3D = Suake2.UI.util.Math3D;
namespace Suake2.UI.server
{
	
	public class SV_GAME
	{
		
		/// <summary> PF_Unicast
		/// 
		/// Sends the contents of the mutlicast buffer to a single client.
		/// </summary>
		public static void  PF_Unicast(edict_t ent, bool reliable)
		{
			int p;
			client_t client;
			
			if (ent == null)
				return ;
			
			p = ent.index;
			if (p < 1 || p > SV_MAIN.maxclients.value_Renamed)
				return ;
			
			client = SV_INIT.svs.clients[p - 1];
			
			if (reliable)
				SZ.Write(client.netchan.message, SV_INIT.sv.multicast.data, SV_INIT.sv.multicast.cursize);
			else
				SZ.Write(client.datagram, SV_INIT.sv.multicast.data, SV_INIT.sv.multicast.cursize);
			
			SZ.Clear(SV_INIT.sv.multicast);
		}
		
		/// <summary> PF_dprintf
		/// 
		/// Debug print to server console.
		/// </summary>
		public static void  PF_dprintf(System.String fmt)
		{
			Com.Printf(fmt);
		}
		
		
		/// <summary> Centerprintf for critical messages.</summary>
		public static void  PF_cprintfhigh(edict_t ent, System.String fmt)
		{
			PF_cprintf(ent, Defines.PRINT_HIGH, fmt);
		}
		
		/// <summary> PF_cprintf
		/// 
		/// Print to a single client.
		/// </summary>
		public static void  PF_cprintf(edict_t ent, int level, System.String fmt)
		{
			
			int n = 0;
			
			if (ent != null)
			{
				n = ent.index;
				if (n < 1 || n > SV_MAIN.maxclients.value_Renamed)
					Com.Error(Defines.ERR_DROP, "cprintf to a non-client");
			}
			
			if (ent != null)
				SV_SEND.SV_ClientPrintf(SV_INIT.svs.clients[n - 1], level, fmt);
			else
				Com.Printf(fmt);
		}
		
		/// <summary> PF_centerprintf
		/// 
		/// centerprint to a single client.
		/// </summary>
		public static void  PF_centerprintf(edict_t ent, System.String fmt)
		{
			int n;
			
			n = ent.index;
			if (n < 1 || n > SV_MAIN.maxclients.value_Renamed)
				return ; // Com_Error (ERR_DROP, "centerprintf to a non-client");
			
			MSG.WriteByte(SV_INIT.sv.multicast, Defines.svc_centerprint);
			MSG.WriteString(SV_INIT.sv.multicast, fmt);
			PF_Unicast(ent, true);
		}
		
		/// <summary>  PF_error
		/// 
		/// Abort the server with a game error. 
		/// </summary>
		public static void  PF_error(System.String fmt)
		{
			Com.Error(Defines.ERR_DROP, "Game Error: " + fmt);
		}
		
		public static void  PF_error(int level, System.String fmt)
		{
			Com.Error(level, fmt);
		}
		
		/// <summary> PF_setmodel
		/// 
		/// Also sets mins and maxs for inline bmodels.
		/// </summary>
		public static void  PF_setmodel(edict_t ent, System.String name)
		{
			int i;
			cmodel_t mod;
			
			if (name == null)
				Com.Error(Defines.ERR_DROP, "PF_setmodel: NULL");
			
			i = SV_INIT.SV_ModelIndex(name);
			
			ent.s.modelindex = i;
			
			// if it is an inline model, get the size information for it
			if (name.StartsWith("*"))
			{
				mod = CM.InlineModel(name);
				Math3D.VectorCopy(mod.mins, ent.mins);
				Math3D.VectorCopy(mod.maxs, ent.maxs);
				SV_WORLD.SV_LinkEdict(ent);
			}
		}
		
		/// <summary>  PF_Configstring</summary>
		public static void  PF_Configstring(int index, System.String val)
		{
			if (index < 0 || index >= Defines.MAX_CONFIGSTRINGS)
				Com.Error(Defines.ERR_DROP, "configstring: bad index " + index + "\n");
			
			if (val == null)
				val = "";
			
			// change the string in sv
			SV_INIT.sv.configstrings[index] = val;
			
			if (SV_INIT.sv.state != Defines.ss_loading)
			{
				// send the update to
				// everyone
				SZ.Clear(SV_INIT.sv.multicast);
				MSG.WriteChar(SV_INIT.sv.multicast, Defines.svc_configstring);
				MSG.WriteShort(SV_INIT.sv.multicast, index);
				MSG.WriteString(SV_INIT.sv.multicast, val);
				
				SV_SEND.SV_Multicast(Globals.vec3_origin, Defines.MULTICAST_ALL_R);
			}
		}
		
		public static void  PF_WriteChar(int c)
		{
			MSG.WriteChar(SV_INIT.sv.multicast, c);
		}
		
		public static void  PF_WriteByte(int c)
		{
			MSG.WriteByte(SV_INIT.sv.multicast, c);
		}
		
		public static void  PF_WriteShort(int c)
		{
			MSG.WriteShort(SV_INIT.sv.multicast, c);
		}
		
		public static void  PF_WriteLong(int c)
		{
			MSG.WriteLong(SV_INIT.sv.multicast, c);
		}
		
		public static void  PF_WriteFloat(float f)
		{
			MSG.WriteFloat(SV_INIT.sv.multicast, f);
		}
		
		public static void  PF_WriteString(System.String s)
		{
			MSG.WriteString(SV_INIT.sv.multicast, s);
		}
		
		public static void  PF_WritePos(float[] pos)
		{
			MSG.WritePos(SV_INIT.sv.multicast, pos);
		}
		
		public static void  PF_WriteDir(float[] dir)
		{
			MSG.WriteDir(SV_INIT.sv.multicast, dir);
		}
		
		public static void  PF_WriteAngle(float f)
		{
			MSG.WriteAngle(SV_INIT.sv.multicast, f);
		}
		
		/// <summary> PF_inPVS
		/// 
		/// Also checks portalareas so that doors block sight.
		/// </summary>
		public static bool PF_inPVS(float[] p1, float[] p2)
		{
			int leafnum;
			int cluster;
			int area1, area2;
			sbyte[] mask;
			
			leafnum = CM.CM_PointLeafnum(p1);
			cluster = CM.CM_LeafCluster(leafnum);
			area1 = CM.CM_LeafArea(leafnum);
			mask = CM.CM_ClusterPVS(cluster);
			
			leafnum = CM.CM_PointLeafnum(p2);
			cluster = CM.CM_LeafCluster(leafnum);
			area2 = CM.CM_LeafArea(leafnum);
			
			// quake2 bugfix
			if (cluster == - 1)
				return false;
			if (mask != null && (0 == (mask[SupportClass.URShift(cluster, 3)] & (1 << (cluster & 7)))))
				return false;
			
			if (!CM.CM_AreasConnected(area1, area2))
				return false; // a door blocks sight
			
			return true;
		}
		
		/// <summary> PF_inPHS.
		/// 
		/// Also checks portalareas so that doors block sound.
		/// </summary>
		public static bool PF_inPHS(float[] p1, float[] p2)
		{
			int leafnum;
			int cluster;
			int area1, area2;
			sbyte[] mask;
			
			leafnum = CM.CM_PointLeafnum(p1);
			cluster = CM.CM_LeafCluster(leafnum);
			area1 = CM.CM_LeafArea(leafnum);
			mask = CM.CM_ClusterPHS(cluster);
			
			leafnum = CM.CM_PointLeafnum(p2);
			cluster = CM.CM_LeafCluster(leafnum);
			area2 = CM.CM_LeafArea(leafnum);
			
			// quake2 bugfix
			if (cluster == - 1)
				return false;
			if (mask != null && (0 == (mask[cluster >> 3] & (1 << (cluster & 7)))))
				return false; // more than one bounce away
			if (!CM.CM_AreasConnected(area1, area2))
				return false; // a door blocks hearing
			
			return true;
		}
		
		public static void  PF_StartSound(edict_t entity, int channel, int sound_num, float volume, float attenuation, float timeofs)
		{
			
			if (null == entity)
				return ;
			SV_SEND.SV_StartSound(null, entity, channel, sound_num, volume, attenuation, timeofs);
		}
		
		
		/// <summary>  SV_ShutdownGameProgs
		/// 
		/// Called when either the entire server is being killed, or it is changing
		/// to a different game directory. 
		/// </summary>
		public static void  SV_ShutdownGameProgs()
		{
			GameBase.ShutdownGame();
		}
		
		/// <summary> SV_InitGameProgs
		/// 
		/// Init the game subsystem for a new map. 
		/// </summary>
		
		public static void  SV_InitGameProgs()
		{
			
			// unload anything we have now
			SV_ShutdownGameProgs();
			
			game_import_t gimport = new game_import_t();
			
			// all functions set in game_export_t (rst)
			GameBase.GetGameApi(gimport);
			
			GameSave.InitGame();
		}
	}
}